<template>
  <div class="news">
    
    
    <div class="container">
      <!-- 面包屑 -->
      <div class="breadcrumb">
        {{$t('breadcrumbHome')}} · {{$t('breadcrumbNews')}}<span v-if="selectedCategory && selectedCategory !== '全部'"> · {{$tCategory(selectedCategory)}}</span>
      </div>

      <div class="news-layout">
        <!-- 左侧分类导航 -->
        <aside class="left-nav">
          <ul class="category-list" role="list">
            <li
              v-for="cat in categories"
              :key="cat"
              :class="['category-item', { active: cat === selectedCategory }]"
              @click="selectCategory(cat)"
              @keydown.enter.prevent="selectCategory(cat)"
              @keydown.space.prevent="selectCategory(cat)"
              :aria-pressed="cat === selectedCategory"
              role="button"
              tabindex="0"
              :title="cat"
            >
              {{ $tCategory(cat) }}
            </li>
          </ul>
        </aside>

        <!-- 主内容区域 -->
        <main class="main-area">
          <div class="toolbar">
            <h1>{{$t('breadcrumbNews')}}</h1>
            <div class="tools">
              <el-input v-model="searchKeyword" :placeholder="$t('searchPlaceholder')" clearable style="width: 260px">
          <template #prefix>
            <el-icon><Search /></el-icon>
          </template>
        </el-input>
              <el-button type="primary" @click="openUploadDialog">
                <el-icon><Plus /></el-icon>
                {{$t('publishNews')}}
              </el-button>
            </div>
      </div>

          <!-- 新闻列表（行型卡片） -->
          <transition-group name="news-fade" tag="div" class="news-list">
            <div class="news-item" v-for="news in paginatedNews" :key="news.id">
              <div class="thumb">
                <img v-if="news.type === 'image'" :src="(news.images && news.images[0]) || news.media" :alt="news.title" />
                <video v-else-if="news.type === 'video'" :src="news.media" controls></video>
              </div>
              <div class="body">
                <h3 class="title" @click="viewNews(news)">{{ displayTitle(news) }}</h3>
                <p class="summary">{{ displaySummary(news) }}</p>
                <div class="meta">
                  <span>{{ news.date }}</span>
                  <span>{{ $tCategory(news.category || '综合') }}</span>
                </div>
              </div>
              <!-- 在新闻列表项的.ops区域添加点赞按钮 -->
              <div class="ops">
                <el-button size="small" @click="viewNews(news)">{{$t('view')}}</el-button>
                <el-button size="small" type="danger" @click="deleteNews(news.id)">{{$t('delete')}}</el-button>
                
                <!-- 新增点赞按钮 -->
                <el-button 
                  size="small" 
                  :type="news.isLiked ? 'primary' : 'default'" 
                  @click="toggleLike(news)"
                  :loading="likeLoading[news.id]"
                >
                  <el-icon><Like /></el-icon>
                  {{ news.likeCount || 0 }}
                </el-button>
              </div>
            </div>
          </transition-group>

          <!-- 分页 -->
          <div class="pagination">
            <el-pagination
              background
              layout="total, sizes, prev, pager, next, jumper"
              :total="filteredNews.length"
              :page-sizes="[6, 9, 12, 24]"
              :page-size="pageSize"
              :current-page="currentPage"
              @current-change="handlePageChange"
              @size-change="handleSizeChange"
            />
          </div>
        </main>

        <!-- 右侧最新动态 -->
        <aside class="right-panel">
          <div class="panel-card">
            <div class="panel-header">{{$t('panelManage')}}</div>
          </div>
          <div class="panel-card">
            <div class="panel-header">{{$t('panelLatest')}}</div>
            <ul class="latest-list">
              <li v-for="n in latestNews" :key="n.id" @click="viewNews(n)">
                <div class="latest-title">{{ displayTitle(n) }}</div>
                <div class="latest-date">{{ n.date }}</div>
              </li>
            </ul>
          </div>
        </aside>
          </div>
            </div>

    <!-- 发布新闻对话框 -->
    <el-dialog v-model="showUploadDialog" :title="$t('publishNews')" width="800px">
      <el-form ref="uploadFormRef" :model="uploadForm" :rules="rules" label-width="100px">
        <el-form-item :label="$t('titleLabel')" prop="title">
          <el-input v-model="uploadForm.title" :placeholder="$t('titlePlaceholder')" maxlength="80" show-word-limit />
        </el-form-item>
        <el-form-item :label="$t('titleEnLabel')">
          <el-input v-model="uploadForm.title_en" placeholder="Title in English" maxlength="120" show-word-limit />
        </el-form-item>
        <el-form-item :label="$t('categoryLabel')" prop="category">
          <el-select v-model="uploadForm.category" :placeholder="$t('categoryPlaceholder')" style="width: 240px">
            <el-option v-for="cat in categories.filter(c => c !== '全部')" :key="cat" :label="$tCategory(cat)" :value="cat" />
          </el-select>
        </el-form-item>
        <el-form-item :label="$t('summaryEnLabel')">
          <el-input v-model="uploadForm.summary_en" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }" maxlength="300" show-word-limit placeholder="Summary in English" />
        </el-form-item>
        <el-form-item :label="$t('typeLabel')" prop="type">
          <el-radio-group v-model="uploadForm.type">
            <el-radio label="image">{{$t('imageLabel')}}</el-radio>
            <el-radio label="video">{{$t('videoLabel')}}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item :label="$t('contentEnLabel')">
          <el-input v-model="uploadForm.content_en" type="textarea" :autosize="{ minRows: 4, maxRows: 8 }" maxlength="4000" show-word-limit placeholder="Content in English" />
        </el-form-item>
        <el-form-item :label="$t('mediaSource')">
          <el-radio-group v-model="mediaMode">
            <el-radio label="upload">{{$t('uploadFile')}}</el-radio>
            <el-radio label="url">{{$t('urlLink')}}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item v-if="mediaMode === 'upload' && uploadForm.type === 'image'" :label="$t('imageLabel')" prop="media">
          <el-upload
            class="media-uploader"
            :auto-upload="false"
            :multiple="true"
            :limit="9"
            :on-change="handleFileChange"
            :on-exceed="onExceed"
            :show-file-list="false"
            accept="image/*"
          >
            <el-button type="primary">{{$t('btnSelectImages')}}</el-button>
          </el-upload>
          <div class="preview-grid" v-if="uploadForm.images && uploadForm.images.length">
            <div class="preview-thumb" v-for="(img, idx) in uploadForm.images" :key="idx">
              <img :src="img" class="preview-image" :alt="$lang.language==='en' ? 'Preview' : '预览'" />
              <el-button text type="danger" class="remove-btn" @click="removeImage(idx)">{{$t('delete')}}</el-button>
            </div>
          </div>
        </el-form-item>
        <el-form-item v-if="mediaMode === 'upload' && uploadForm.type === 'video'" :label="$t('videoLabel')" prop="media">
          <el-upload
            class="media-uploader"
            :auto-upload="false"
            :limit="1"
            :on-change="handleFileChange"
            :on-exceed="onExceed"
            :show-file-list="false"
            accept="video/*"
          >
            <template v-if="!uploadForm.media">
              <el-button type="primary">{{$t('btnSelectVideo')}}</el-button>
            </template>
            <template v-else>
              <video :src="uploadForm.media" class="preview-video" controls />
            </template>
          </el-upload>
        </el-form-item>
        <el-form-item v-if="mediaMode === 'url' && uploadForm.type === 'image'" :label="$t('imageUrlLabel')">
          <el-input v-model="uploadUrlsText" type="textarea" :autosize="{minRows:2,maxRows:6}" :placeholder="$t('imagesUrlPlaceholder')" />
          <div style="margin-top:8px">
            <el-button @click="applyUrlList">{{$t('btnImportUrl')}}</el-button>
            <el-button @click="autoTranslateToEn" type="default" style="margin-left:8px">{{$t('autoTranslate')}}</el-button>
          </div>
        </el-form-item>
        <el-form-item v-if="mediaMode === 'url' && uploadForm.type === 'video'" :label="$t('videoUrlLabel')" prop="media">
          <el-input v-model="uploadForm.media" :placeholder="$t('videoUrlPlaceholder')" />
        </el-form-item>
        <el-form-item :label="$t('contentLabel')" prop="content">
          <el-input v-model="uploadForm.content" type="textarea" :autosize="{ minRows: 4, maxRows: 8 }" maxlength="2000" show-word-limit :placeholder="$t('contentPlaceholder')" />
          <div v-if="uploadForm.type === 'image' && uploadForm.images && uploadForm.images.length" class="content-insert">
            <div class="content-insert-title">{{$t('contentInsertTitle')}}</div>
            <div class="preview-grid">
              <div class="preview-thumb" v-for="(img, idx) in uploadForm.images" :key="idx">
                <img :src="img" class="preview-image" alt="图" />
                <el-button size="small" @click="insertImageIntoContent(idx)">{{$t('btnInsert')}}</el-button>
        </div>
      </div>
    </div>
        </el-form-item>
        <el-form-item :label="$t('summaryLabel')">
          <el-input v-model="uploadForm.summary" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }" maxlength="200" show-word-limit :placeholder="$lang.language==='en' ? 'Short summary for list' : '用于列表的简短摘要'" />
        </el-form-item>
        <el-form-item :label="$t('authorLabel')">
          <el-input v-model="uploadForm.author" :placeholder="$t('authorPlaceholder')" style="width: 240px" />
        </el-form-item>
        <el-form-item :label="$t('sourceLabel')">
          <el-input v-model="uploadForm.source" :placeholder="$t('sourcePlaceholder')" style="width: 240px" />
        </el-form-item>
        <el-form-item :label="$t('tagsLabel')">
          <el-select v-model="uploadForm.tags" multiple filterable allow-create default-first-option :placeholder="$t('tagsPlaceholder')" style="width: 100%" />
        </el-form-item>
        <el-form-item :label="$t('publishDateLabel')">
          <el-date-picker v-model="uploadForm.date" type="date" value-format="YYYY-MM-DD" :placeholder="$lang.language==='en' ? 'Select date' : '选择发布日期'" />
        </el-form-item>
        <el-form-item :label="$t('pinLabel')">
          <el-switch v-model="uploadForm.isTop" />
        </el-form-item>
        <el-form-item :label="$t('statusLabel')">
          <el-select v-model="uploadForm.status" style="width: 200px">
            <el-option :label="$lang.language==='en' ? 'Draft' : '草稿'" value="draft" />
            <el-option :label="$lang.language==='en' ? 'Published' : '发布'" value="published" />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="previewFromForm">{{$t('btnPreview')}}</el-button>
          <el-button @click="resetUploadForm">{{$t('btnReset')}}</el-button>
          <el-button @click="saveDraft">{{$t('btnSaveDraft')}}</el-button>
          <el-button @click="closeUploadDialog">{{$t('btnCancel')}}</el-button>
          <el-button type="primary" @click="submitNews">{{$t('btnPublish')}}</el-button>
        </span>
      </template>
    </el-dialog>

    <!-- 详情对话框 -->
    <el-dialog v-model="showDetailDialog" :title="(currentNews && currentNews.title) || ($lang.language==='en' ? 'News Detail' : '新闻详情')" width="700px">
      <div class="detail-content" v-if="currentNews">
        <div class="detail-media">
          <template v-if="currentNews.type === 'image'">
            <img v-for="(img,idx) in (currentNews.images || [currentNews.media])" :key="idx" :src="img" class="detail-image" :alt="currentNews.title" />
          </template>
          <video v-else :src="currentNews.media" class="detail-video" controls />
        </div>
        <div class="detail-meta">
          <span>{{$lang.language==='en' ? 'Published:' : '发布日期：'}}{{ currentNews.date }}</span>
          <span>{{$lang.language==='en' ? 'Type:' : '类型：'}}{{ currentNews.type === 'image' ? ($lang.language==='en'?'Image':'图文') : ($lang.language==='en'?'Video':'视频') }}</span>
        </div>
        <div class="detail-text" v-html="renderContent($lang.language==='en' && currentNews.content_en ? currentNews.content_en : currentNews.content)"></div>
      </div>
      <!-- 在详情对话框的footer前添加 -->
      <div class="detail-actions" v-if="currentNews">
        <el-button 
          :type="currentNews.isLiked ? 'primary' : 'default'" 
          @click="toggleLike(currentNews)"
          :loading="likeLoading[currentNews.id]"
        >
          <el-icon><Like /></el-icon>
          {{ currentNews.likeCount || 0 }}
        </el-button>
      </div>
      <template #footer>
        <el-button type="primary" @click="showDetailDialog = false">{{$lang.language==='en' ? 'Close' : '关 闭'}}</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script>
export default {
  name: 'News',
  data() {
    return {
      filterType: 'all',
      searchKeyword: '',
      categories: ['全部', '图片新闻', '时政要闻', '农科要闻', '科研活动', '三农一线', '媒体报道', '视频农科', '政务新媒体矩阵'],
      selectedCategory: '全部',
      // 控制是否启用后端接口调用
      enableNewsApi: (typeof process !== 'undefined' && process.env && process.env.VUE_APP_ENABLE_NEWS_API === 'true') || localStorage.getItem('enableNewsApi') === 'true',
      newsList: [
        {
          id: 1,
          title: '2024年小麦品质检测新标准发布',
          content: '国家发布最新小麦品质检测标准，提升检测精度和效率。',
          type: 'image',
          media: 'https://images.unsplash.com/photo-1581094794329-c8112a89af12?w=600&h=400&fit=crop',
          date: '2024-01-15',
          category: '农科要闻'
        },
        {
          id: 2,
          title: '新型检测设备投入使用',
          content:  '引进国际先进检测设备，大幅提升检测准确性和效率。',
          type: 'video',
          media: 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4',
          date: '2024-01-10',
          category: '科研活动'
        },
        {
          id: 3,
          title: '茶多酚自组装材料可用于水果保鲜',
          content: '中国农业科学院茶叶研究所团队提出新材料解决方案，用于水果保鲜与品质提升。',
          type: 'image',
          media: 'https://images.unsplash.com/photo-1506806732259-39c2d0268443?w=600&h=400&fit=crop',
          date: '2024-01-08',
          category: '媒体报道'
        }
      ],
      // 发布对话框
      showUploadDialog: false,
      uploadForm: {
        title: '',
        title_en: '',
        content: '',
        content_en: '',
        summary: '',
        summary_en: '',
        type: 'image',
        media: '',
        images: [],
        imageFiles: [],
        videoFile: null, // 单独存储视频文件
        category: '',
        author: '',
        source: '',
        tags: [],
        date: '',
        isTop: false,
        status: 'published'
      },
      uploadUrlsText: '',
      rules: {
        title: [ { required: true, message: '请输入标题', trigger: 'blur' } ],
        category: [ { required: true, message: '请选择分类', trigger: 'change' } ],
        type: [ { required: true, message: '请选择类型', trigger: 'change' } ],
        media: [ { required: false, message: '请上传或填写媒体', trigger: 'change' } ],
        content: [ { required: true, message: '请输入正文内容', trigger: 'blur' } ]
      },
      mediaMode: 'upload',
      // 上传状态管理
      uploadImageStatus: [], // 图片上传状态: ready/uploading/success/error
      videoUploadStatus: 'ready', // 视频上传状态
      uploadProgress: 0, // 上传进度百分比
      isUploading: false, // 整体上传状态
      // 详情对话框
      showDetailDialog: false,
      currentNews: null,
      // 分页
      currentPage: 1,
      pageSize: 9,
      loading: false, // 列表加载状态
      total: 0, // 总记录数
      // 点赞相关状态
      likeLoading: {}, // 存储每个新闻的点赞加载状态
      currentUser: { id: 1 }, // 当前登录用户信息，实际项目从登录状态获取

    }
  },
  computed: {
    filteredNews() {
      let filtered = this.newsList
      
      if (this.selectedCategory && this.selectedCategory !== '全部') {
        filtered = filtered.filter(news => (news.category || '') === this.selectedCategory)
      }
      
      if (this.filterType !== 'all') {
        filtered = filtered.filter(news => news.type === this.filterType)
      }
      
      if (this.searchKeyword) {
        filtered = filtered.filter(news => 
          news.title.toLowerCase().includes(this.searchKeyword.toLowerCase())
        )
      }
      
      return filtered
    },
    paginatedNews() {
      const startIndex = (this.currentPage - 1) * this.pageSize
      return this.filteredNews.slice(startIndex, startIndex + this.pageSize)
    },
    latestNews() {
      const sorted = [...this.newsList].sort((a, b) => 
        (b.isTop === true) - (a.isTop === true) || 
        (b.date || '').localeCompare(a.date || '')
      )
      return sorted.slice(0, 6)
    }
  },
  mounted() {
    this.fetchNewsList();
  },
  methods: {
    // 提交新闻（核心发布逻辑）
  async submitNews() {
    // 表单验证
    const form = this.$refs.uploadFormRef
    if (form && form.validate) {
      const valid = await form.validate().catch(() => false)
      if (!valid) return
    }

    // 处理媒体文件（上传本地文件到服务器）
    try {
      await this.processMediaUploads()
    } catch (error) {
      this.$message.error(this.$t('msgMediaUploadFailed'))
      return
    }

    // 构建新闻数据对象
    const newsData = this.buildNewsData()

    // 保存到服务器
    try {
      // 显示提交中状态
      this.isSubmitting = true;
      
      // 调用后端/create接口
      const { data } = await this.$axios.post('/news/create', newsData);
      
      // 处理后端响应
      if (data && data.code === 1) {

        // 本地数据更新
        this.updateLocalNewsList(newsData)
        this.$message.success(this.$t('msgPublished') + ': ' + (data.msg || ''))
        this.closeUploadDialog()
      } else {
        // 后端返回失败状态
        this.$message.error(this.$t('msgPublishFailed') + ': ' + (data?.msg || '未知错误'))
        console.error('发布失败，后端返回:', data)
      }
    } catch (error) {
      // 网络错误或异常处理
      let errorMsg = '网络错误';
      if (error.response) {
        errorMsg = `服务器错误 (${error.response.status})`;
      } else if (error.message) {
        errorMsg = error.message;
      }
      
      this.$message.error(this.$t('msgPublishFailed') + ': ' + errorMsg)
      console.error('发布失败:', error)
    } finally {
      // 隐藏提交状态
      this.isSubmitting = false;
    }
  },

    // 处理媒体文件（上传本地文件）
    async processMediaUploads() {
      if (this.mediaMode === 'upload') {
        if (this.uploadForm.type === 'image') {
          await this.uploadImageFiles()
        } else if (this.uploadForm.type === 'video') {
          await this.uploadVideoFile()
        }
      }
    },

    // 批量上传图片
    async uploadImageFiles() {
      if (!Array.isArray(this.uploadForm.images) || this.uploadForm.images.length === 0) {
        return [];
      }

      const uploadedUrls = [];
      
      for (let i = 0; i < this.uploadForm.images.length; i++) {
        const src = this.uploadForm.images[i];
        const file = this.uploadForm.imageFiles[i];
        
        // 仅上传本地选择的文件（blob开头的预览链接）
        if (src.startsWith('blob:') && file) {
          try {
            // 更新上传状态
            this.uploadImageStatus[i] = 'uploading';
            
            // 提取文件扩展名（如.jpg、.png）
            const fileExtension = this.getFileExtension(file);
            
            // 构建FileVO对象，添加storeType参数
            const fileVO = {
              type: 'image',
              name: file.name,
              size: file.size,
              fileType: file.type,
              storeType: fileExtension // 设置为具体的图片类型
            };
            
            // 调用上传方法
            const url = await this.uploadSingleFile(file, fileVO);
            uploadedUrls.push(url);
            
            // 更新上传状态为成功
            this.uploadImageStatus[i] = 'success';
          } catch (error) {
            // 更新上传状态为失败
            this.uploadImageStatus[i] = 'error';
            throw error; // 抛出错误，中断批量上传
          }
        } else {
          // 已经是网络URL，直接使用
          uploadedUrls.push(src);
          this.uploadImageStatus[i] = 'success';
        }
      }
      
      this.uploadForm.images = uploadedUrls;
      return uploadedUrls;
    },

    // 上传视频文件
    async uploadVideoFile() {
      if (!this.uploadForm.media || !this.uploadForm.videoFile) {
        return null;
      }

      // 仅上传本地选择的文件
      if (this.uploadForm.media.startsWith('blob:')) {
        try {
          this.videoUploadStatus = 'uploading';
          
          // 提取视频文件扩展名
          const fileExtension = this.getFileExtension(this.uploadForm.videoFile);
          
          // 构建FileVO对象，添加storeType参数
          const fileVO = {
            type: 'video',
            name: this.uploadForm.videoFile.name,
            size: this.uploadForm.videoFile.size,
            fileType: this.uploadForm.videoFile.type,
            storeType: fileExtension // 设置为具体的视频类型
          };
          
          const url = await this.uploadSingleFile(this.uploadForm.videoFile, fileVO);
          this.uploadForm.media = url;
          this.videoUploadStatus = 'success';
          return url;
        } catch (error) {
          this.videoUploadStatus = 'error';
          throw error;
        }
      }
      
      // 已经是网络URL，直接使用
      return this.uploadForm.media;
    },

    // 上传单个文件到服务器
    async uploadSingleFile(file, fileVO = {}) {
      if (!file || !this.$axios) {
        throw new Error('文件不存在或请求工具未初始化');
      }

      // 创建FormData对象，用于提交multipart/form-data类型数据
      const formData = new FormData();
      
      // 添加文件参数，对应后端@RequestParam("file")
      formData.append('file', file);
      
      // 添加FileVO参数，后端会自动映射
      if (fileVO) {
        Object.keys(fileVO).forEach(key => {
          if (fileVO[key] !== undefined && fileVO[key] !== null) {
            formData.append(key, fileVO[key]);
          }
        });
      }

      try {
        // 显示加载状态
        this.isUploading = true;
        
        // 调用后端接口
        const { data } = await this.$axios.post('/resource/upload', formData, {

          headers: {
            'Content-Type': 'multipart/form-data'
          },
          // 添加上传进度监听
          onUploadProgress: (progressEvent) => {
            if (progressEvent.lengthComputable) {
              const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total);
              this.uploadProgress = percent;
            }
          }
        });

        console.log(data)

        // 检查响应结果
        if (data && data.code === 1) {
          this.$message.success(this.$t('msgUploadSuccess'));
          return data.data; // 返回后端返回的文件URL
        } else {
          this.$message.error(data?.message || this.$t('msgUploadFailed'));
          throw new Error(data?.message || '文件上传失败');
        }
      } catch (error) {
        console.error('文件上传失败:', error);
        this.$message.error(this.$t('msgUploadError'));
        throw error;
      } finally {
        // 隐藏加载状态
        this.isUploading = false;
        this.uploadProgress = 0;
      }
    },

    // 构建新闻数据对象（适配后端News实体类）
    buildNewsData() {
      const now = new Date();
      const today = now.toISOString().split('T')[0]; // 格式: YYYY-MM-DD
      const currentDateTime = now.toISOString(); // 格式: YYYY-MM-DDTHH:mm:ss.sssZ（符合LocalDateTime格式）
      // 处理图集（将数组转为JSON字符串，适配后端images字段）
      const imagesJson = this.uploadForm.type === 'image' && Array.isArray(this.uploadForm.images) 
        ? JSON.stringify(this.uploadForm.images) 
        : null;
      // 处理封面图（取第一张图片作为封面）
      const coverImage = this.uploadForm.type === 'image' && Array.isArray(this.uploadForm.images) && this.uploadForm.images.length > 0
        ? this.uploadForm.images[0]
        : null;
      return {
        // 基本信息
        title: this.uploadForm.title,
        content: this.uploadForm.content,
        // 作者信息（根据实际登录状态填充，这里用示例值）
        authorId: this.currentUser?.id || 1, // 假设当前用户ID
        authorName: this.uploadForm.author || this.currentUser?.name || '管理员',
         // 媒体资源
        coverImage: coverImage,                // 封面图
        images: imagesJson,                    // 图集（JSON字符串）
        videoUrl: this.uploadForm.type === 'video' ? this.uploadForm.media : null, // 视频URL
        // 统计数据（初始值）
        viewCount: 0,
        likeCount: 0,
        commentCount: 0,
        collectCount: 0,
        sortWeight: 0, // 排序权重默认0
        // 状态标识
        isTop: this.uploadForm.isTop || false,
        isRecommend: false, // 默认为不推荐
        isHot: false,       // 默认为非热门
        // 时间字段（后端LocalDateTime兼容ISO格式字符串）
        publishTime: this.uploadForm.date 
          ? new Date(this.uploadForm.date).toISOString() 
          : currentDateTime,
        isDeleted: 0 // 默认为未删除
      };
    },

    // 保存新闻到服务器
    async saveNewsToServer(newsData) {
      if (!this.enableNewsApi || !this.$axios) {
        return Promise.resolve() // 模拟成功
      }

      const { data } = await this.$axios.post('/api/news', newsData)
      if (!data.success) {
        throw new Error(data.message || '保存失败')
      }
      return data.data
    },

    // 更新本地新闻列表
    updateLocalNewsList(newsData) {
      // 添加到列表开头
      this.newsList.unshift(newsData)
      // 保持列表排序（置顶在前，按日期排序）
      this.newsList.sort((a, b) => {
        if (a.isTop !== b.isTop) {
          return b.isTop - a.isTop
        }
        return new Date(b.date) - new Date(a.date)
      })
    },

    // 处理文件选择
    handleFileChange(file) {
      const rawFile = file.raw || file;
      if (!rawFile) return;

      // 验证文件类型
      const isImage = rawFile.type.startsWith('image/');
      const isVideo = rawFile.type.startsWith('video/');
      if (!isImage && !isVideo) {
        this.$message.error(this.$t('msgOnlyImageVideo'));
        return;
      }

      // 验证文件大小
      const maxSize = isImage ? 5 * 1024 * 1024 : 50 * 1024 * 1024; // 图片5MB，视频50MB
      if (rawFile.size > maxSize) {
        this.$message.error(this.$t(isImage ? 'msgImageTooLarge' : 'msgVideoTooLarge'));
        return;
      }

      // 处理图片
      if (isImage) {
        this.handleImageFile(rawFile);
      }
      // 处理视频
      else if (isVideo) {
        this.handleVideoFile(rawFile);
      }
    },

    // 处理图片文件
    handleImageFile(file) {
      // 创建预览
      const url = URL.createObjectURL(file);
      
      // 初始化数组（容错处理）
      if (!Array.isArray(this.uploadForm.images)) this.uploadForm.images = [];
      if (!Array.isArray(this.uploadForm.imageFiles)) this.uploadForm.imageFiles = [];
      if (!Array.isArray(this.uploadImageStatus)) this.uploadImageStatus = [];
      
      // 添加到表单
      const index = this.uploadForm.images.length;
      this.uploadForm.images.push(url);
      this.uploadForm.imageFiles.push(file);
      this.uploadImageStatus[index] = 'ready'; // 上传状态：ready/uploading/success/error
      
      // 检查是否超过限制
      if (this.uploadForm.images.length > 9) {
        this.uploadForm.images = this.uploadForm.images.slice(0, 9);
        this.uploadForm.imageFiles = this.uploadForm.imageFiles.slice(0, 9);
        this.uploadImageStatus = this.uploadImageStatus.slice(0, 9);
        this.onExceed();
      }
    },

    // 处理视频文件
    handleVideoFile(file) {
      // 创建预览
      const url = URL.createObjectURL(file);
      this.uploadForm.media = url;
      this.uploadForm.videoFile = file; // 保存文件引用，用于后续上传
      this.videoUploadStatus = 'ready'; // 视频上传状态
    },

    // 显示标题（多语言支持）
    displayTitle(item) {
      if (this.$lang?.language === 'en' && item.title_en) return item.title_en;
      return item.title;
    },

    // 显示摘要（多语言支持）
    displaySummary(item) {
      if (this.$lang?.language === 'en' && item.summary_en) return item.summary_en;
      // 若没有英文摘要，退化到中文摘要或中文内容
      return item.summary || item.content;
    },

    // 渲染内容（处理HTML和Markdown）
    renderContent(raw) {
      if (!raw) return '';
      let html = String(raw);
      // 将被转义的 HTML 实体还原
      if (html.includes('&lt;') || html.includes('&amp;')) {
        html = this.decodeHtmlEntities(html);
      }
      // 支持 Markdown 图片语法 -> <img>
      html = html.replace(/!\[[^\]]*\]\(([^)]+)\)/g, `<img src="$1" alt="${this.$lang && this.$lang.language === 'en' ? 'image' : '图片'}" />`);
      // 换行转 <br/>
      html = html.replace(/\n/g, '<br/>');
      // 去除 script
      html = html.replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, '');
      // 为 img 补充懒加载与样式
      html = html.replace(/<img(?![^>]*\bloading=)[^>]*>/gi, (m) => {
        // 已有 style 则不重复添加 max-width 样式
        if (/style=/.test(m)) return m.replace('<img', '<img loading="lazy"');
        return m.replace('<img', '<img loading="lazy" style="max-width:100%;height:auto;"');
      });
      return html;
    },

    // 解码HTML实体
    decodeHtmlEntities(str) {
      const div = document.createElement('div');
      div.innerHTML = str;
      let text = div.textContent || div.innerText || '';
      // 手动转换实体字符
      text = text
        .replace(/&lt;/g, '<')
        .replace(/&gt;/g, '>')
        .replace(/&amp;/g, '&')
        .replace(/&quot;/g, '"')
        .replace(/&#39;/g, "'");
      return text;
    },

    // 选择分类
    selectCategory(cat) {
      this.selectedCategory = cat;
      this.currentPage = 1;
    },

    // 打开上传对话框
    openUploadDialog() {
      this.showUploadDialog = true;
    },

    // 关闭上传对话框
    closeUploadDialog() {
      this.showUploadDialog = false;
      this.resetUploadForm();
    },

    // 重置上传表单
    resetUploadForm() {
      this.mediaMode = 'upload';
      this.uploadForm = { 
        title: '', 
        content: '', 
        summary: '', 
        type: 'image', 
        media: '', 
        images: [], 
        imageFiles: [], 
        videoFile: null,
        category: '', 
        author: '', 
        source: '', 
        tags: [], 
        date: '', 
        isTop: false, 
        status: 'published' 
      };
      this.uploadUrlsText = '';
      this.uploadImageStatus = [];
      this.videoUploadStatus = 'ready';
    },

    // 移除图片
    removeImage(index) {
      if (!Array.isArray(this.uploadForm.images)) return;
      const url = this.uploadForm.images[index];
      if (url && typeof url === 'string' && url.startsWith('blob:')) {
        try { URL.revokeObjectURL(url); } catch (_) {}
      }
      this.uploadForm.images.splice(index, 1);
      if (Array.isArray(this.uploadForm.imageFiles)) {
        this.uploadForm.imageFiles.splice(index, 1);
      }
      if (Array.isArray(this.uploadImageStatus)) {
        this.uploadImageStatus.splice(index, 1);
      }
    },

    // 应用URL列表
    applyUrlList() {
      const urls = (this.uploadUrlsText || '')
        .split(/\r?\n/)
        .map(s => s.trim())
        .filter(Boolean);
      if (!urls.length) {
        this.$message.warning(this.$t('msgNeedImageUrl'));
        return;
      }
      if (!Array.isArray(this.uploadForm.images)) this.uploadForm.images = [];
      if (!Array.isArray(this.uploadForm.imageFiles)) this.uploadForm.imageFiles = [];
      const capacity = 9 - this.uploadForm.images.length;
      const append = urls.slice(0, Math.max(0, capacity));
      this.uploadForm.images.push(...append);
      this.uploadForm.imageFiles.push(...new Array(append.length).fill(null));
      this.$message.success(this.$lang.language === 'en' ? `Imported ${append.length} images` : `已导入 ${append.length} 张图片`);
    },

    // 自动翻译到英文
    async autoTranslateToEn() {
      // 简易自动翻译：占位逻辑
      if (!this.uploadForm.title_en) this.uploadForm.title_en = this.uploadForm.title;
      if (!this.uploadForm.summary_en) this.uploadForm.summary_en = this.uploadForm.summary || (this.uploadForm.content || '').slice(0, 120);
      if (!this.uploadForm.content_en) this.uploadForm.content_en = this.uploadForm.content;
      this.$message.success(this.$t('msgDraftSaved'));
    },

    // 插入图片到内容
    // 插入图片到内容
    async insertImageIntoContent(index) {
      const src = this.uploadForm.images?.[index];
      if (!src) return;
      let finalUrl = src;
      // 若是 blob: 且允许后端，尝试上传换成可持久化 URL
      if (String(src).startsWith('blob:') && this.enableNewsApi) {
        const file = this.uploadForm.imageFiles?.[index];
        try {
          // 提取文件扩展名
          const fileExtension = this.getFileExtension(file);
          
          const fileVO = {
            type: 'image',
            name: file.name,
            size: file.size,
            fileType: file.type,
            storeType: fileExtension // 设置为具体的图片类型
          };
          const uploaded = await this.uploadSingleFile(file, fileVO);
          if (uploaded) finalUrl = uploaded;
        } catch (_) {}
      }
      const newline = this.uploadForm.content && !this.uploadForm.content.endsWith('\n') ? '\n' : '';
      this.uploadForm.content = (this.uploadForm.content || '') + `${newline}<p><img src="${finalUrl}" alt="${this.$lang && this.$lang.language === 'en' ? 'image' : '图片'}"/></p>\n`;
      this.$message.success(this.$t('msgInsertOk'));
    },

    // 新增方法：提取文件扩展名
    getFileExtension(file) {
      if (!file || !file.name) return '';
      
      // 从文件名提取（如"image.jpg" -> ".jpg"）
      const lastDotIndex = file.name.lastIndexOf('.');
      if (lastDotIndex > 0) {
        return file.name.slice(lastDotIndex).toLowerCase();
      }
      
      // 从MIME类型提取（如"image/png" -> ".png"）
      if (file.type && file.type.includes('/')) {
        const mimeParts = file.type.split('/');
        if (mimeParts.length > 1) {
          return `.${mimeParts[1].toLowerCase()}`;
        }
      }
      
      // 默认返回空或通用类型
      return file.type.startsWith('image/') ? '.jpg' : '';
    },

    // 文件超出限制处理
    onExceed() {
      if (this.uploadForm.type === 'image') {
        this.$message.warning(this.$t('msgMaxImages'));
      } else {
        this.$message.warning(this.$t('msgMaxOneFile'));
      }
    },

    // 保存草稿
    saveDraft() {
      // 仅校验基本字段
      if (!this.uploadForm.title) {
        this.$message.warning(this.$t('msgFillTitle'));
        return;
      }
      const draftKey = 'newsDrafts';
      const list = JSON.parse(localStorage.getItem(draftKey) || '[]');
      list.unshift({ ...this.uploadForm, savedAt: Date.now() });
      localStorage.setItem(draftKey, JSON.stringify(list));
      this.$message.success(this.$t('msgDraftSaved'));
    },

    // 预览表单内容
    previewFromForm() {
      if (!this.uploadForm.title) {
        this.$message.warning(this.$t('msgFillTitle'));
        return;
      }
      this.currentNews = {
        id: 0,
        title: this.uploadForm.title,
        content: this.uploadForm.content,
        type: this.uploadForm.type,
        media: this.uploadForm.media,
        date: this.uploadForm.date || '',
        category: this.uploadForm.category || '',
      };
      this.showDetailDialog = true;
    },

    // 查看新闻详情
    viewNews(news) {
      this.currentNews = news;
      this.showDetailDialog = true;
    },

        // 删除新闻（完善版：本地+后端联动）
      deleteNews(id) {
      // 1. 弹出确认弹窗
      this.$confirm(
        this.$t('confirmDeleteText'), // 确认删除文案（如“确定要删除这条新闻吗？删除后不可恢复”）
        this.$t('confirmTitle'),     // 弹窗标题（如“确认删除”）
        {
          confirmButtonText: this.$t('okText'),       // 确认按钮文案（如“确定”）
          cancelButtonText: this.$t('cancelText'),   // 取消按钮文案（如“取消”）
          type: 'warning',                           // 弹窗类型（警告色）
          closeOnClickModal: false,                  // 点击弹窗外部不关闭（防止误操作）
          distinguishCancelAndClose: true            // 区分“取消”和“关闭”按钮
        }
      )
      .then(async () => {
        // 2. 显示加载状态（优化用户感知）
        this.loading = true;
        try {
          // 3. 调用后端删除接口（对应Controller的 /news/{id} DELETE接口）
          const { data } = await this.$axios.delete(`/news/${id}`); // 注意：路径需与后端Controller一致（之前Controller定义的是 /api/news/{id}）
          
          // 4. 处理后端响应（根据实际后端返回格式调整，这里假设后端返回 {code: 1, msg: "成功"}）
          if (data && data.code === 1) {
            // 5. 后端删除成功后，同步删除本地列表数据
            this.newsList = this.newsList.filter(news => news.id !== id);
            // 6. 同步更新本地存储（避免页面刷新后数据恢复）
            localStorage.setItem('newsList', JSON.stringify(this.newsList));
            // 7. 提示删除成功
            this.$message.success(this.$t('msgDeleted')); // 如“新闻删除成功”
          } else {
            // 8. 后端返回失败（如权限不足、新闻不存在）
            this.$message.error(`${this.$t('msgDeleteFailed')}: ${data?.msg || '未知错误'}`); // 如“删除失败：新闻不存在”
          }
        } catch (error) {
          // 9. 捕获网络异常（如接口不通、500错误）
          let errorMsg = this.$t('msgNetworkError'); // 如“网络异常，请稍后重试”
          if (error.response) {
            // 根据HTTP状态码细化提示
            if (error.response.status === 404) {
              errorMsg = this.$t('msgNewsNotFound'); // 如“新闻不存在或已被删除”
            } else if (error.response.status === 403) {
              errorMsg = this.$t('msgNoDeletePermission'); // 如“无删除权限”
            } else if (error.response.status === 500) {
              errorMsg = this.$t('msgServerError'); // 如“服务器错误，请联系管理员”
            }
          }
          this.$message.error(`${this.$t('msgDeleteFailed')}: ${errorMsg}`);
          console.error('删除新闻异常:', error); // 控制台打印异常，便于调试
        } finally {
          // 10. 无论成功/失败，都关闭加载状态
          this.loading = false;
        }
      })
      .catch(action => {
        // 11. 取消删除（用户点击“取消”或关闭弹窗）
        if (action === 'cancel') { // 点击“取消”按钮
          this.$message.info(this.$t('msgDeleteCancelled')); // 如“已取消删除”
        } else if (action === 'close') { // 点击弹窗关闭按钮
          this.$message.info(this.$t('msgOperationCancelled')); // 如“已取消操作”
        }
      });
    },

    // 获取新闻列表
    fetchNewsList() {
      this.loading = true;
      return this.$axios.get('/news/page', {
        query: {
          category: this.selectedCategory === '全部' ? null : this.selectedCategory,
          searchKeyword: this.searchKeyword
        },
        pageNum: this.currentPage,
        pageSize: this.pageSize
      })
      .then(response => {
        this.newsList = response.data.data.records;
        this.total = response.data.data.total;
      })
      .catch(error => {
        console.error('获取新闻列表失败:', error);
        this.$message.error('获取新闻列表失败');
      })
      .finally(() => {
        this.loading = false;
      });
    },

    // 分页改变
    handlePageChange(page) {
      this.currentPage = page;
      this.fetchNewsList();
    },

    // 页大小改变
    handleSizeChange(size) {
      this.pageSize = size;
      this.fetchNewsList();
    },

    // 尝试从API获取新闻
    async tryFetchNewsApi() {
      try {
        if (!this.$axios || !this.enableNewsApi) return;
        const { data } = await this.$axios.get('/news');
        if (Array.isArray(data) && data.length) {
          this.newsList = data;
        }
      } catch (e) {
        // 忽略后端不可用的情况，使用本地数据
      }
    },

    // 尝试创建新闻到API
    async tryCreateNewsApi(payload) {
      try {
        if (!this.$axios || !this.enableNewsApi) return;
        await this.$axios.post('/news', payload);
      } catch (e) {}
    },

    // 尝试从API删除新闻
    async tryDeleteNewsApi(id) {
      try {
        if (!this.$axios || !this.enableNewsApi) return;
        await this.$axios.delete(`/news/${id}`);
      } catch (e) {}
    },

    // 图片压缩处理
    resizeImageToBlob(file, maxWidth = 1200, maxHeight = 800, quality = 0.9) {
      return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = () => {
          const img = new Image();
          img.onload = () => {
            const widthRatio = maxWidth / img.width;
            const heightRatio = maxHeight / img.height;
            const ratio = Math.min(1, widthRatio, heightRatio);
            const targetWidth = Math.round(img.width * ratio);
            const targetHeight = Math.round(img.height * ratio);
            const canvas = document.createElement('canvas');
            canvas.width = targetWidth;
            canvas.height = targetHeight;
            const ctx = canvas.getContext('2d');
            if (!ctx) return reject(new Error('canvas unsupported'));
            ctx.drawImage(img, 0, 0, targetWidth, targetHeight);
            canvas.toBlob((blob) => {
              if (blob) resolve(blob);
              else reject(new Error('toBlob failed'));
            }, file.type.includes('png') ? 'image/png' : 'image/jpeg', quality);
          };
          img.onerror = reject;
          img.src = reader.result;
        };
        reader.onerror = reject;
        reader.readAsDataURL(file);
      });
    }
  },
  created() {
    // 读取本地存储的新闻列表
    const saved = localStorage.getItem('newsList');
    if (saved) {
      try {
        const parsed = JSON.parse(saved);
        if (Array.isArray(parsed)) {
          this.newsList = parsed;
        }
      } catch (_) {}
    }
    // 可用则尝试从后端获取
    if (this.enableNewsApi) {
      this.tryFetchNewsApi();
    }
  },
  watch: {
    newsList: {
      handler(newVal) {
        localStorage.setItem('newsList', JSON.stringify(newVal));
      },
      deep: true
    }
  }
}
</script>


<style scoped>
.news {
  min-height: 100vh;
  background: #f5f5f5;
}

.container {
  max-width: 1400px;
  margin: 0 auto;
  padding: 2rem;
}

.breadcrumb {
  color: #ffffff;
  background: #145a50;
  border: 1px solid #145a50;
  padding: 10px 14px;
  border-radius: 6px;
  margin-bottom: 16px;
}

.news-layout {
  display: grid;
  grid-template-columns: 220px 1fr 320px;
  gap: 20px;
}

.left-nav .category-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.category-item {
  position: relative;
  background: #1c7f73;
  color: #fff;
  margin-bottom: 12px;
  border-radius: 10px;
  padding: 14px 16px 14px 18px;
  cursor: pointer;
  transition: transform .15s ease, background .2s ease, color .2s ease, box-shadow .2s ease, border-color .2s ease;
  box-shadow: 0 2px 6px rgba(0,0,0,0.06);
  border: 1px solid transparent;
}
.category-item:hover { background: #239989; }
.category-item:focus { outline: none; box-shadow: 0 0 0 3px rgba(35,153,137,.25); }
.left-nav { position: sticky; top: 16px; align-self: start; padding-left: 26px; }
.left-nav::before {
  content: '';
  position: absolute;
  left: 10px;
  top: 0;
  bottom: 0;
  width: 2px;
  background: #d6eee9;
}
.category-item.active {
  background: #fff;
  color: #1c7f73;
  border-color: #cfe7e1;
}
.category-item.active::after {
  content: '';
  position: absolute;
  left: -18px;
  top: 50%;
  transform: translateY(-50%);
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #1c7f73;
  box-shadow: 0 0 0 3px #fff;
}

.main-area .toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}
.main-area .toolbar h1 {
  font-size: 22px;
  color: #2b3a42;
}
.main-area .tools { display: flex; gap: 12px; }

.news-list { display: flex; flex-direction: column; gap: 16px; }
.news-item {
  display: grid;
  grid-template-columns: 280px 1fr auto;
  gap: 16px;
  background: #fff;
  border-radius: 8px;
  border: 1px solid #e6efec;
  box-shadow: 0 6px 14px rgba(0,0,0,0.05);
  padding: 14px;
}
.thumb { width: 100%; height: 160px; overflow: hidden; border-radius: 6px; }
.thumb img, .thumb video { width: 100%; height: 100%; object-fit: cover; }
.body .title { font-size: 18px; margin: 2px 0 8px; color: #234; cursor: pointer; }
.body .summary {
  color: #5f6e73; line-height: 1.7; margin-bottom: 10px;
  display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.body .meta { color: #8a9a9f; font-size: 13px; display: flex; gap: 16px; }
.ops { display: flex; align-items: center; gap: 8px; }

.pagination { display: flex; justify-content: center; margin: 14px 0 6px; }

.right-panel { display: flex; flex-direction: column; gap: 16px; }
.panel-card { background: #fff; border: 2px solid #e6efec; border-radius: 8px; }
.panel-header { background: #1c7f73; color: #fff; padding: 10px 14px; border-radius: 8px 8px 0 0; font-weight: 600; }
.latest-list { list-style: none; padding: 0 14px 10px; margin: 0; }
.latest-list li { padding: 12px 0; border-bottom: 1px dashed #e5eeea; cursor: pointer; }
.latest-title { color: #2a3a41; font-size: 14px; line-height: 1.5; }
.latest-date { color: #8aa; font-size: 12px; margin-top: 4px; }

/* 上传预览图等比显示 */
.preview-image {
  width: 200px;
  height: 140px;
  object-fit: contain;
  background: #f6f8f7;
  border: 1px solid #e6efec;
  border-radius: 6px;
}

.preview-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 10px;
  margin-top: 10px;
}
.preview-thumb { position: relative; }
.preview-thumb .remove-btn { position: absolute; top: 4px; right: 4px; }

.content-insert { margin-top: 8px; }
.content-insert-title { color: #6b7; margin-bottom: 6px; font-size: 13px; }

.detail-text img {
  max-width: 100%;
  height: auto;
  display: block;
  margin: 8px 0;
  border-radius: 6px;
}

@media (max-width: 768px) {
  .news-layout { grid-template-columns: 1fr; }
  .news-item { grid-template-columns: 1fr; }
}

/* 列表过渡动画 */
.news-fade-enter-active, .news-fade-leave-active { transition: all .25s ease; }
.news-fade-enter-from { opacity: 0; transform: translateY(8px); }
.news-fade-leave-to { opacity: 0; transform: translateY(-8px); }
</style>